#pragma once
#include <vector>
#include <cassert>
#include <iostream>
#include <cstring>

namespace str
{
#define CAPACITY 15
	class String
	{
	public:
		String() : _capacity(CAPACITY), _size(0), _length(0), _str(nullptr)
		{
			reserve(_capacity);
		}

		String(const char *s) : _capacity(CAPACITY), _size(0), _length(0), _str(nullptr)
		{
			assert(s != nullptr);
			reserve(_capacity);
			size_t n = strlen(s);
			reserve(n);
			while (*s != '\0')
			{
				push_back(*s);
				s++;
			}
		}

		String(const String &str) : _capacity(str.capacity()), _size(0), _length(0), _str(nullptr)
		{
			reserve(_capacity);
			size_t size = str.size();
			resize(size);
			for (int i = 0; i < size; i++)
			{
				_str[i] = str[i];
			}
		}

		String(size_t n, char c)
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				push_back(c);
			}
		}

		~String()
		{
			delete _str;
			_size = 0;
			_capacity = 0;
			_length = 0;
		}

		String &assign(const String &str)
		{
			reserve(str.capacity());
			size_t size = str.size();
			resize(size);
			for (size_t i = 0; i < size; i++)
			{
				_str[i] = str[i];
			}
			return *this;
		}

		String &replace(size_t pos, size_t len, const String &str)
		{
			if (pos > _size)
			{
				throw std::out_of_range("Position is out of range");
			}
			size_t offset = 0;
			if (str.size() > len)
				offset = str.size() - len;
			else
				offset = len - str.size();
			if (str.size() > len) resize(_size + offset);
			if (str.size() > len)
			{
				// 右移
				for (size_t i = _size - 1; i >= pos + len; i--)
				{
					_str[i + offset] = _str[i];
				}
			}
			else
			{
				for (size_t i = pos + len; i < _size; i++)
				{
					_str[i - offset] = _str[i];
					std::cout << i - offset << ' ' << i << std::endl;
				}
			}
			for (size_t i = 0; i < str.size(); i++)
			{
				_str[i + pos] = str[i];
			}
			if (str.size() < len) resize(_size - offset);
			return *this;
		}

		char &operator[](size_t pos)
		{
			return *(_str + pos);
		}

		const char &operator[](size_t pos) const
		{
			return *(_str + pos);
		}

		char &at(size_t pos)
		{
			return *(_str + pos);
		}

		const char &at(size_t pos) const
		{
			return *(_str + pos);
		}

		String &operator+=(const String &str)
		{
			size_t size = str.size();
			reserve(_size + size);
			for (size_t i = 0; i < size; i++)
			{
				push_back(str[i]);
			}
			return *this;
		}

		const char *c_str() const
		{
			_str[_size] = '\0';
			return _str;
		}

		const char *data() const
		{
			return _str;
		}

		void push_back(char c)
		{
			if (_size == _capacity)
				reserve(_size + 1);
			_str[_size] = c;
			_size++;
		}

		void pop_back()
		{
			resize(_size - 1);
		}

		String &append(const String &str)
		{
			reserve(_size + str.size());
			return operator+=(str);
		}

		void reserve(size_t n)
		{
			if (n < _capacity)
				return;
			size_t newcapacity = _capacity;
			while (newcapacity < n)
			{
				newcapacity *= 2;
			}
			if (_str == nullptr)
			{
				char *newstr = (char *)malloc(newcapacity * sizeof(char));
				if (newstr == nullptr)
				{
					perror("malloc空指针\n");
					exit(-1);
				}
				_str = newstr;
				newstr = nullptr;
			}
			else
			{
				char *newstr = (char *)realloc(_str, newcapacity * sizeof(char));
				if (newstr == nullptr)
				{
					perror("realloc空指针\n");
					exit(-1);
				}
				_str = newstr;
				newstr = nullptr;
			}
			_capacity = newcapacity;
		}

		void resize(size_t n, char c = '\0')
		{
			if (n < _size)
			{
				_size = n;
			}
			else
			{
				reserve(n);
				while (_size != n)
				{
					push_back(c);
				}
			}
		}

		void clear()
		{
			resize(0);
		}

		size_t capacity() const noexcept
		{
			return _capacity;
		}

		size_t size() const noexcept
		{
			return _size;
		}

		size_t length()
		{
			return _length;
		}

	private:
		char *_str;
		size_t _capacity;
		size_t _size;
		size_t _length;
	};

	std::ostream &operator<<(std::ostream &os, const String &str)
	{
		os << str.c_str();
		return os;
	}
}